/*
 * Copyright (c) 2012 Joe Kopena <tjkopena@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.rocketshipgames.haxe.ds;

class Deadpool<T: (DeadpoolObject)>
{

  //------------------------------------------------------------
  private var totalList:List<T>;
  private var freeList:List<T>;
  private var instantiate:Array<Dynamic>->T;

  //--------------------------------------------------------------------
  //------------------------------------------------------------
  public function new(instantiate:Array<Dynamic>->T):Void
  {
    this.instantiate = instantiate;
    totalList = new List();
    freeList = new List();
    // end new
  }

  public function hasFree():Bool { return freeList.isEmpty(); }

  public function lengthAll():Int { return totalList.length; }
  public function iteratorAll():Iterator<T> { return totalList.iterator(); }

  //--------------------------------------------------------------------
  public function newObject(opts:Array<Dynamic> = null):T
  {
    var object:T;

    if (freeList.isEmpty()) {
      object = instantiate(opts);
      object.setDeadpool(this);
      totalList.push(object);
    } else {
      object = freeList.pop();
      object.init(opts);
    }

    return object;
    // end newObject
  }

  public function returnObject(object:T):Void
  {
    // Note that in general for very large sets it makes sense to
    // reuse the most recently used object, so it's still in cache.
    freeList.push(object);
    // end returnObject
  }

  // end Deadpool
}
